package com.qc.pay;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.qc.common.MD5Utils;
import com.qc.common.StringUtil;
import com.qc.common.Util;
import com.qc.common.WebUtil;
import com.qc.common.XmlUtil;
import com.qc.entity.WXPayEntity;

public class WXPayUtil {

	public static final String ORDER_PAY = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 统一下单

	public static final String ORDER_PAY_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery"; // 支付订单查询

	public static final String ORDER_REFUND = "https://api.mch.weixin.qq.com/secapi/pay/refund"; // 申请退款

	public static final String ORDER_REFUND_QUERY = "https://api.mch.weixin.qq.com/pay/refundquery"; // 申请退款

	public static final String APP_ID = "wx379b943f5f22a6bb";

	public static final String MCH_ID = "1439824302";//商户ID

	public static final String API_SECRET = "d8d77691c132e07af2a9a076974b4e24";
	public static final String KEY = "d8d77691c132e07af2a9a076974b4e24"; //商户API安全设置的密钥
	
	private static SSLContext wx_ssl_context = null; //微信支付ssl证书
	
	private static final String notify_url = "http://139.224.237.223:8080/69mark/WXpayNotifyCallBack";
	
	static{
		Resource resource = new ClassPathResource("wx_apiclient_cert.p12");
		try {
			KeyStore keystore = KeyStore.getInstance("PKCS12");
			char[] keyPassword = MCH_ID.toCharArray(); //证书密码（商户ID）
			keystore.load(resource.getInputStream(), keyPassword);
			wx_ssl_context = SSLContexts.custom().loadKeyMaterial(keystore, keyPassword).build();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static Map<String, String> sendOrder(WXPayEntity entity, HttpServletRequest request) {
		try {
			String total_fee = BigDecimal.valueOf(entity.getPrice()).multiply(BigDecimal.valueOf(100))
					.setScale(0, BigDecimal.ROUND_HALF_UP).toString();
			Map<String, String> parm = new HashMap<String, String>();
			parm.put("appid", APP_ID);
			parm.put("mch_id", MCH_ID);
            parm.put("device_info", entity.getDeviceType());
            parm.put("nonce_str", Util.getNonceStr());
			parm.put("body", "聘请订单");
//			parm.put("attach", "Andy");
            parm.put("out_trade_no", entity.getOrderNumber());
            parm.put("total_fee", total_fee);
			parm.put("spbill_create_ip", Util.getRemoteAddrIp(request));
			parm.put("notify_url", notify_url); //微信服务器异步通知支付结果地址  下面的order/notify 方法
			parm.put("trade_type", "APP");
			String signStr = getSign(parm, KEY);
			parm.put("sign", signStr);

//			WebUtil.post(ORDER_PAY, XmlUtil.xmlFormat(parm, false));
			String restxml = WebUtil.sendPost(ORDER_PAY, XmlUtil.xmlFormat(parm, false));
			return XmlUtil.xmlParse(restxml);
		} catch (Exception e) {
			Util.logExceptionINFO(e);
		}
		return null;
	}
	
	public static Map<String, String> refundOrder(String orderNumber, double price) {
		try {
			String total_fee = BigDecimal.valueOf(price).multiply(BigDecimal.valueOf(100))
					.setScale(0, BigDecimal.ROUND_HALF_UP).toString();
			Map<String, String> parm = new HashMap<String, String>();
			parm.put("appid", APP_ID);
			parm.put("mch_id", MCH_ID);
            parm.put("nonce_str", Util.getNonceStr());
			parm.put("out_trade_no", orderNumber);//订单号
			parm.put("out_refund_no", orderNumber); //退款单号
			parm.put("total_fee", total_fee); // 订单总金额 从业务逻辑获取
			parm.put("refund_fee", total_fee); // 退款金额
			parm.put("op_user_id", MCH_ID);
			String signStr = getSign(parm, KEY);
			parm.put("sign", signStr);
			
			String restxml = posts(ORDER_REFUND, XmlUtil.xmlFormat(parm, false));
			System.out.println("申请退款微信返回:"+restxml);
			return XmlUtil.xmlParse(restxml);
		} catch (Exception e) {
			Util.logExceptionINFO(e);
		}
		return null;
	}
	
	public static String getSign(Map<String, String> params, String paternerKey) throws UnsupportedEncodingException {
		return MD5Utils.getMD5(createSign(params, false) + "&key=" + paternerKey).toUpperCase();
	}
	
	/**
	 * 构造签名
	 * 
	 * @param params
	 * @param encode
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String createSign(Map<String, String> params, boolean encode) throws UnsupportedEncodingException {
		Set<String> keysSet = params.keySet();
		Object[] keys = keysSet.toArray();
		Arrays.sort(keys);
		StringBuffer temp = new StringBuffer();
		boolean first = true;
		for (Object key : keys) {
			if (key == null || StringUtil.isEmpty(params.get(key))) // 参数为空不参与签名
				continue;
			if (first) {
				first = false;
			} else {
				temp.append("&");
			}
			temp.append(key).append("=");
			Object value = params.get(key);
			String valueStr = "";
			if (null != value) {
				valueStr = value.toString();
			}
			if (encode) {
				temp.append(URLEncoder.encode(valueStr, "UTF-8"));
			} else {
				temp.append(valueStr);
			}
		}
		return temp.toString();
	}
	
	/**
	 * @description 功能描述: post https请求，服务器双向证书验证
	 * @param url 请求地址
	 * @param s 参数xml
	 * @return 请求失败返回null
	 */
	public static String posts(String url, String s) {
		CloseableHttpClient httpClient = null;
		HttpPost httpPost = new HttpPost(url);
		String body = null;
		CloseableHttpResponse response = null;
		try {
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
	        		wx_ssl_context,
	                new String[] { "TLSv1" },
	                null,
	                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
			httpClient = HttpClients.custom()
	                .setSSLSocketFactory(sslsf)
	                .build();
			httpPost.setEntity(new StringEntity(s, "UTF-8")); 
			response = httpClient.execute(httpPost);
			body = EntityUtils.toString(response.getEntity(), "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if (httpClient != null) {
				try {
					httpClient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return body;
	}
}
